#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
The input pad for TUI module.
"""

# Author: Likayo Lee

__all__ = {"InputPad"}

import curses, curses.textpad, curses.ascii
import locale
import os

class Validator:
    def __init__(self, textpad, multiline, debug_win=None):
        """
        Initialize a validator for an InputPad object.
        
        Args:
            textpad: an InputPad instance.
            multiline: whether multiline input is allowed. If not allowed,
                the return key will ternimate the input.
            debug_win: a window to print debug infomation.
        """
        self.textpad = textpad
        self.debug = debug_win
        self.multiline = multiline

    def validate(self, ch):
        (y, x) = self.textpad.win.getyx()
        orig_ch = ch
        edited = False
        if ch == curses.ascii.NL and not self.multiline:
            ch = curses.ascii.BEL
        elif ch == curses.ascii.ESC:
            ch = curses.ascii.BEL
            self.textpad.abort = True
        elif self.textpad.history and ch == curses.KEY_UP:  # history exists and 
                                                            # log number >= 1 
            if self.textpad.history_i == -1:
                self.textpad.history_i = len(self.textpad.history)
            self.textpad.history_i = max(self.textpad.history_i - 1, 0)
            self.textpad.win.erase()
            self.textpad.win.addstr(self.textpad.history[self.textpad.history_i])
            self.textpad.win.refresh()
        elif self.textpad.history and ch == curses.KEY_DOWN:
            if self.textpad.history_i == -1:
                pass
            else:
                self.textpad.history_i = min(self.textpad.history_i + 1, 
                                            len(self.textpad.history) - 1)
                self.textpad.win.erase()
                self.textpad.win.addstr(self.textpad.history[self.textpad.history_i])
                self.textpad.win.refresh()
        # TODO(likayo): deal with KEY_RESIZE
        # TODO(likayo): deal with utf8 wide getch
        else:
            edited = True

        if edited:
            self.textpad.history_i = -1


        # if self.debug != None:
        #     try:
        #         if orig_ch == ch:
        #             self.debug.addstr("%d " % ch)
        #         else:
        #             self.debug.addstr("%d->%d " % (orig_ch, ch))
        #     except curses.error:
        #         self.debug.erase()
        #     self.debug.refresh()

        return ch


class InputPad(object):
    def __init__(self, height, width, init_y, init_x,
                    multiline, history=False, debug_win=None):
        """
        Args:
            multiline: whether multi-line input is allowed.
        """
        self.win        = curses.newwin(height, width, init_y, init_x)   # for convenience
        self._text      = curses.textpad.Textbox(self.win, insert_mode=True)
        self._debug     = debug_win
        self._validator = Validator(self, multiline, self._debug)
        self.abort      = False
        self.history   = [] if history else None
        self.history_i = -1
        # if self.debug != None:
        #     self.debug.addstr(repr(self.__dict___))
        #     self.debug.refresh()

    def edit(self):
        """
        Interact with user input to get a string.

        Returns:
            If input succeeded, return the rstrip-ed input string. 
            If the input process is interrupted by ESC, return integer 1.
        """
        self.abort = False
        self._text.win.erase()
        s = self._text.edit(lambda ch: self._validator.validate(ch)).rstrip()
        if self.abort:
            return 1
        else:
            if self.history is not None:
                self.history.append(s)
            return s


def test_inputpad(stdscr, encoding):
    textpad_h = 3
    
    debug_msg = curses.newwin(10,60,10,1)
    inputpad = InputPad(2, 15, 0, 0, multiline=False, debug_win=debug_msg)
    # inputpad.win.move(15,0)
    # debug_msg.addstr(repr(inputpad.win.getmaxyx()))
    # v = Validator(inputpad, debug_msg)
    while True:
        t = inputpad.edit()
        stdscr.erase()
        stdscr.addstr(5, 0, repr(t))
        # inputpad.win.erase()
        # inputpad.win.refresh()
        debug_msg.erase()
        debug_msg.refresh()
        stdscr.refresh()
        

if __name__ == '__main__':
    # a trick to reduce the delay for escape key.
    # for more details, see http://en.chys.info/2009/09/esdelay-ncurses/
    os.environ["ESCDELAY"] = "25"

    locale.setlocale(locale.LC_ALL, '')
    code = locale.getpreferredencoding()
    curses.wrapper(test_inputpad, code)

    print "death"